package merisis.contentcloud;

import static junit.framework.Assert.assertEquals;
import merisis.util.BitUtil;

import org.apache.solr.util.OpenBitSet;
import org.junit.Assert;
import org.junit.Test;

public class ContentCloudTest1 extends AbstractContentCloudTest {

	@Test
	public void case1() {

		long occurrence;

		assertEquals(1, nm("content-type"));
		assertEquals(2, nm("tag"));
		assertEquals(3, nm("pdf"));

		assertEquals(4, nm("tom"));

		assertEquals(5, nm("doc1"));
		assertEquals(6, nm("doc1-1.0"));

		// ////////////////////////////////////////////////////////////
		/* Scene-1: The 'doc1' is created, of which the version is 1 */
		mvm.give(nm("tom"));
		mvm.stepin();
		try {
			long doc1 = cloud.occur("a"); // the doc1's content
			assertEquals(7, doc1);

			// the editor set the properties.
			occurrence = mvm.occur(doc1, nm("content-type"), nm("pdf"));
			assertEquals(8, occurrence);

			// tom give it a tag
			occurrence = mvm.occur(doc1, mvm.occur(nm("tag"), nm("doc1")));
			assertEquals(10, occurrence);
		} finally {
			mvm.stepout();
		}

		dumpHistory("** Scene-1 History **", 0, 40);

		// /////////////////////////////////////////////////////////////
		/* Scene-2: The 'doc1' is modified, of which the version is 2 */
		mvm.give(nm("tom"));
		mvm.stepin();
		try {
			long[] docs = findLatestPdfDocByLable(nm("doc1"));
			Assert.assertNotNull(docs);
			long doc1 = docs[0];
			Assert.assertEquals(7L, doc1);
			Assert.assertEquals("a", cloud.retrieve(doc1));

			mvm.give(doc1);
			mvm.stepin();
			try {
				long doc = cloud.occur("ab");
				assertEquals(11L, doc);

				occurrence = mvm.occur(doc, nm("content-type"), nm("pdf"));
				assertEquals(12, occurrence);
			} finally {
				mvm.stepout();
			}

			// the editor set the properties.

		} finally {
			mvm.stepout();
		}

		dumpHistory("** Scene-2 History **", 0, 40);

		// /////////////////////////////////////////////////////////////
		/* Scene-3: The 'doc1' is modified, of which the version is 2 */
		mvm.give(nm("tom"));
		mvm.stepin();
		try {
			long[] docs = findLatestPdfDocByLable(nm("doc1"));
			Assert.assertNotNull(docs);
			long doc1 = docs[0];
			Assert.assertEquals(11L, doc1);
			Assert.assertEquals("ab", cloud.retrieve(doc1));

			mvm.give(doc1);
			mvm.stepin();
			try {
				long doc = cloud.occur("abc"); // append char 'c'
				assertEquals(13L, doc);

				// The system describs the modification
				occurrence = mvm.occur(doc, nm("content-type"), nm("pdf"));
				assertEquals(14, occurrence);
			} finally {
				mvm.stepout();
			}
		} finally {
			mvm.stepout();
		}

		// /////////////////////////////////////////////////////////////
		/* Scene-4: The 'doc1' is modified, of which the version is 2 */
		mvm.give(nm("tom"));
		mvm.stepin();
		try {
			long[] docs = findLatestPdfDocByLable(nm("doc1"));
			Assert.assertNotNull(docs);
			long doc1 = docs[0];
			Assert.assertEquals(13L, doc1);
			Assert.assertEquals("abc", cloud.retrieve(doc1));

			mvm.give(doc1);
			mvm.stepin();
			try {
				// tom gives the doc a tag 'doc1-1.0'
				occurrence = mvm.occur(doc1, mvm.occur(nm("tag"),
						nm("doc1-1.0")));
				assertEquals(16, occurrence);
			} finally {
				mvm.stepout();
			}
		} finally {
			mvm.stepout();
		}

		mvm.give(nm("tom"));
		mvm.stepin();
		try {
			long[] docs = findLatestPdfDocByLable(nm("doc1"));
			Assert.assertNotNull(docs);
			long doc1 = docs[0];
			Assert.assertEquals(13L, doc1);

			docs = findLatestPdfDocByLable(nm("doc1-1.0"));
			Assert.assertNotNull(docs);
			doc1 = docs[0];
			Assert.assertEquals(13L, doc1);
		} finally {
			mvm.stepout();
		}
		
		dumpHistory("** Scene-4 History **", 0, 100);

		mvm.give(nm("tom"));
		mvm.stepin();
		try {
			Assert.assertEquals(7L, findExactPdfDocByLable(nm("doc1")));
			Assert.assertEquals(13L, findExactPdfDocByLable(nm("doc1-1.0")));
		} finally {
			mvm.stepout();
		}
	}

	private long[] findLatestPdfDocByLable(long lbl) {

		mvm.give(nm("tag"), lbl);
		mvm.source();
		mvm.focus();
		mvm.autobeam();
		mvm.give(lbl, nm("tag"));
		mvm.complement();

		long[] prop1 = mvm.read();
		Assert.assertNotNull(prop1);

		logger.fine("tag's content:" + BitUtil.toString(prop1));

		OpenBitSet bs = new OpenBitSet();
		for (int i = 0; i < prop1.length; i++) {

			mvm.give(prop1[i], nm("content-type"), nm("pdf"));
			mvm.source();
			mvm.focus();
			mvm.autobeam();
			mvm.give(nm("pdf"), nm("content-type"));
			mvm.complement();
			long[] prop2 = mvm.read();
			if (prop2 == null)
				continue;

			for (int j = 0; j < prop2.length; j++) {
				bs.set(prop2[j]);
			}
		}

		logger.fine("latest pdf: " + BitUtil.toString(bs));

		return BitUtil.toArray(bs);
	}

	private long findExactPdfDocByLable(long lbl) {
		
		mvm.give(nm("tag"), lbl);
		mvm.source();
		mvm.focus();
		mvm.autobeam();
		mvm.give(lbl, nm("tag"));
		mvm.complement();

		long[] prop1 = mvm.read();
		Assert.assertNotNull(prop1);

		logger.fine("tag spectrum:" + BitUtil.toString(prop1));

		OpenBitSet bs = new OpenBitSet();
		for (int i = 0; i < prop1.length; i++) {

			mvm.give(prop1[i], nm("content-type"), nm("pdf"));
			mvm.source();
			mvm.focus();
			mvm.autobeam();
			mvm.give(nm("pdf"), nm("content-type"));	
			mvm.complement();
			long[] prop2 = mvm.read();
			if (prop2 == null)
				continue;

			for (int j = 0; j < prop2.length; j++) {
				bs.set(prop1[i]);
				break;
			}
		}

		logger.fine("exact pdf: " + BitUtil.toString(bs));

		return bs.nextSetBit(0);
	}
}
